#include "YM2612StateData.h"
#include "YM2612Value.h"
//-------------------------------------------------------------------------------------------------------
//YM2612StateData - Initializes and keeps track of all the data representing
//					the state of a YM2612 at any given time.
//-------------------------------------------------------------------------------------------------------
YM2612StateData::YM2612StateData()
{
	//Initialize state properties for global parameters
	StateProps[0].Init( CHAN01_EN, 0, 1, 1 );
	StateProps[1].Init( CHAN02_EN, 0, 1, 1 );
	StateProps[2].Init( CHAN03_EN, 0, 1, 1 );
	StateProps[3].Init( CHAN04_EN, 0, 1, 1 );
	StateProps[4].Init( CHAN05_EN, 0, 1, 1 );
	StateProps[5].Init( CHAN06_EN, 0, 1, 1 );
	StateProps[6].Init( INS_TAB_SEL01, 0, 1, 1 );
	StateProps[7].Init( INS_TAB_SEL02, 0, 1, 0 );
	StateProps[8].Init( INS_TAB_SEL03, 0, 1, 0 );
	StateProps[9].Init( INS_TAB_SEL04, 0, 1, 0 );
	StateProps[10].Init( INS_TAB_SEL05, 0, 1, 0 );
	StateProps[11].Init( INS_TAB_SEL06, 0, 1, 0 );
	StateProps[12].Init( EMULATION_MODE, 0, 1, 1 );
	StateProps[13].Init( SPECIAL_MODE, 0, 1, 0 );		 
					 
	//Initialize param indexes
	int index = 0;
	MinParmIndex = index;
	for( int iChan = 0; iChan < 6; iChan++ )
	{
		for( int iOp = 0; iOp < 4; iOp++ )
		{
			for( int iParm = 0; iParm < Channels[iChan].Operators[iOp].NumParams(); iParm++ )
			{
				Channels[iChan].Operators[iOp][iParm]->SetIndex(index);
				Channels[iChan].Operators[iOp][iParm]->SetOwner(this);
				IndexMap[index] = Channels[iChan].Operators[iOp][iParm];
				index++;
			}
			Channels[iChan].Operators[iOp].SetChannel(iChan);
			Channels[iChan].Operators[iOp].SetOp(iOp);
		}
	}
	MaxParmIndex = index;

	//Initialize algorithm indexes
	MinAlgIndex = index;
	for( int iChan = 0; iChan < 6; iChan++ )
	{
		for( int iAlg = 0; iAlg < Channels[iChan].Algorithm.NumParams(); iAlg++ )
		{
			Channels[iChan].Algorithm[iAlg]->SetIndex(index);
			Channels[iChan].Algorithm[iAlg]->SetOwner(this);
			IndexMap[index] = Channels[iChan].Algorithm[iAlg];
			index++;
		}
		Channels[iChan].Algorithm.SetChannel(iChan);
	}
	MaxAlgIndex = index;

	//Initialize state props
	MinStatePropsIndex = index;
	for( int iChan = 0; iChan < 6; iChan++ )
	{
		StateProps[iChan].SetIndex(index);
		StateProps[iChan].SetOwner(this);
		StateProps[iChan].SetChannel(iChan);
		IndexMap[index] = &StateProps[iChan];
		index++;
	}

	MinStatePropsInsSelIndex = index;
	for( int i = 0; i < 6; i++ )
	{
		StateProps[6 + i].SetIndex(index);
		StateProps[6 + i].SetOwner(this);
		IndexMap[index] = &StateProps[6 + i];
		index++;
	}
	MaxStatePropsInsSelIndex = index;
	MaxStatePropsIndex = index;

	//Initialize channel params
	for( int iChan = 0; iChan < 6; iChan++ )
	{
		for( int iParm = 0; iParm < Channels[iChan].NumParams(); iParm++ )
		{
			Channels[iChan][iParm]->SetIndex(index);
			Channels[iChan][iParm]->SetOwner(this);
			IndexMap[index] = Channels[iChan][iParm];
			index++;
		}
	}

	for( int i = 0; i < 6; i++ )
	{
		for( int j = 0; j < Instruments[i].NumParams(); j++ )
		{
			Instruments[i][j]->SetIndex(index);
			Instruments[i][j]->SetOwner(this);
			IndexMap[index] = Instruments[i][j];
			index++;
		}
	}

	StateProps[12].SetIndex(index);
	StateProps[12].SetOwner(this);
	IndexMap[index] = &StateProps[12];
	index++;
				
	StateProps[13].SetIndex(index);
	StateProps[13].SetOwner(this);
	IndexMap[index] = &StateProps[13];
	index++;
		
	MaxIndex = index;
}

//-------------------------------------------------------------------------

int YM2612StateData::GetParmOpIndex( int channel, YM2612Param parm, int op )
{
	if( parm > ALGS_MIN && parm < ALGS_MAX )
		return Channels[channel].Algorithm.GetParam(parm).GetIndex();

	if( parm > STATE_PROPS_MIN && parm < STATE_PROPS_MAX )
		return StateProps[(parm - STATE_PROPS_MIN) - 1].GetIndex();

	if( parm > CHANNEL_PROPS_MIN && parm < CHANNEL_PROPS_MAX )
		return Channels[channel].GetParam(parm).GetIndex();

	if( parm > INSTRUMENT_PROPS_MIN && parm < INSTRUMENT_PROPS_MAX )
		return Instruments[op].GetParam(parm).GetIndex();


	return Channels[channel].Operators[op].GetParam(parm).GetIndex();
}

//-------------------------------------------------------------------------

YM2612Value* YM2612StateData::GetValueByIndex( int index )
{
	if( index >= MaxIndex )
		return nullptr; 

	return IndexMap[index];
}

//-------------------------------------------------------------------------

YM2612Value* YM2612StateData::GetMidiLearn()
{
	for( auto it = MidiControls.begin(); it != MidiControls.end(); it++ )
	{
		YM2612Value* val = (*it).first;
		if( val != nullptr && val->GetMidiLearn() == true )
			return val;
	}
	return nullptr;
}

//-------------------------------------------------------------------------

void YM2612StateData::GetMidiHookups(int hook, std::vector<YM2612Value*>& out) const
{
	for( auto it = MidiControls.begin(); it != MidiControls.end(); it++ )
	{
		YM2612Value* val = (*it).first;
		if( val != nullptr && val->GetMidiHookup() == hook )
			out.push_back(val);
	}
}

//-------------------------------------------------------------------------

int YM2612StateData::GetSelectedInstrument() const
{
	for( int i = 6; i < 12; i++ )
	{
		if(StateProps[i].GetValue() > 0.01f)
			return i - 6;
	}
	return 0;
}

//-------------------------------------------------------------------------

int YM2612StateData::GetNumParms()
{
	//Since the number of parameters relies completely on the implementation
	//of the initialization of YM2612StateData, we need to construct one here
	//to get the max index.
	YM2612StateData dat;
	return dat.MaxIndex;
}

//-------------------------------------------------------------------------